package gosm

import (
	"bufio"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"gitee.com/zhouhailin/gopkg/gosm/sm"
	"gitee.com/zhouhailin/gopkg/gosm/sm2"
	"gitee.com/zhouhailin/gopkg/gosm/sm3"
	"gitee.com/zhouhailin/gopkg/gosm/sm4"
	"io"
	"os"
)

func SM2GenerateKey() (string, string, error) {
	priv, pub, err := sm2.GenerateKey(rand.Reader)
	if err != nil {
		return "", "", err
	}
	return base64.StdEncoding.EncodeToString(priv.GetRawBytes()), base64.StdEncoding.EncodeToString(pub.GetRawBytes()), nil
}

func SM2Encode(publicKey string, value string) (string, error) {
	publicKey1, err := base64.StdEncoding.DecodeString(publicKey)
	if err != nil {
		return "", err
	}
	pubKey, err := sm2.RawBytesToPublicKey(publicKey1)
	if err != nil {
		return "", err
	}
	encrypt, err := sm2.Encrypt(pubKey, []byte(value), sm2.C1C3C2)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(encrypt), nil
}

func SM2Decode(privateKey string, value string) (string, error) {
	privateKey1, err := base64.StdEncoding.DecodeString(privateKey)
	if err != nil {
		return "", err
	}
	privKey, err := sm2.RawBytesToPrivateKey(privateKey1)
	if err != nil {
		return "", err
	}
	if value == "" {
		return "", nil
	}
	decrypt2, err := base64.StdEncoding.DecodeString(value)
	if err != nil {
		return "", err
	}

	decrypt, err := sm2.Decrypt(privKey, decrypt2, sm2.C1C3C2)
	if err != nil {
		return "", err
	}
	return string(decrypt), nil
}

func SM3(str string) string {
	return fmt.Sprintf("%x", sm3.Sum([]byte(str)))
}

func SM3File(file *os.File) (string, error) {
	hash := sm3.New()
	reader := bufio.NewReader(file)
	buffer := make([]byte, 10*1024) // 10KB 缓冲区
	for {
		n, err := reader.Read(buffer)
		if n > 0 {
			if _, err := hash.Write(buffer[:n]); err != nil {
				return "", err
			}
		}
		if err == io.EOF {
			return fmt.Sprintf("%x", hash.Sum(nil)), nil
		}
		if err != nil {
			return "", err
		}
	}
}

func SM4GenerateKey() (string, error) {
	key := make([]byte, 16)
	_, err := io.ReadFull(rand.Reader, key)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(key), nil
}

func SM4Encode(key string, value string) (string, error) {
	key0, err := base64.StdEncoding.DecodeString(key)
	if err != nil {
		return "", err
	}
	in := []byte(value)
	plainTextWithPadding := sm.PKCS5Padding(in, sm4.BlockSize)
	cipherText, err := sm4.ECBEncrypt(key0, plainTextWithPadding)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(cipherText), nil
}

func SM4Decode(key string, value string) (string, error) {
	key0, err := base64.StdEncoding.DecodeString(key)
	if err != nil {
		return "", err
	}
	decodeString, err := base64.StdEncoding.DecodeString(value)
	if err != nil {
		return "", err
	}
	plainTextWithPadding, err := sm4.ECBDecrypt(key0, decodeString)
	if err != nil {
		return "", err
	}
	return string(sm.PKCS5UnPadding(plainTextWithPadding)), nil
}
